package com.example.d3_collection_list;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * LinkedList的源码分析
 */
@SuppressWarnings({"all"})
public class LinkedListSource {
    public static void main(String[] args) {

        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList=" + linkedList);

        // 演示一个删除结点的
        linkedList.remove(); // 这里默认删除的是第一个结点
        // linkedList.remove(2);

        System.out.println("linkedList=" + linkedList);

        // 修改某个结点对象
        linkedList.set(1, 999);
        System.out.println("linkedList=" + linkedList);

        // 得到某个结点对象
        // get(1) 是得到双向链表的第二个对象
        Object o = linkedList.get(1);
        System.out.println(o); //999

        // 因为LinkedList 是 实现了List接口, 遍历方式
        System.out.println("===LinkeList遍历迭代器====");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println("next=" + next);

        }

        System.out.println("===LinkeList遍历增强for====");
        for (Object o1 : linkedList) {
            System.out.println("o1=" + o1);
        }

        System.out.println("===LinkeList遍历普通for====");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }


        //源码分析
        /* 1. LinkedList linkedList = new LinkedList();
              public LinkedList() {

              }
           2. 这时 linkeList 的属性 first = null  last = null
           3. 执行 添加
               public boolean add(E e) {
                    //这里就是真正添加的方法
                    linkLast(e);
                    return true;
                }
            4.将新的结点,加入到双向链表的最后


// 在添加第二个元素时 final Node<E> l = last;//此时last还是空
// 紧接着创建了一个新的节点 final Node<E> newNode = new Node<>(l, e, null); 此时l作为指向第一个节点的引用赋给了第二个节点pre的位置
// 这个时候新节点的pre就指向了,第一个节点,
// 紧接着last = newNode;就是让last指向新的节点
// 这个时候判断l是否等于空很显然,l指向了第一个节点,此时不为空
// 因此执行l.next=new newNode 也就是让l执行新节点的next因为在这个之前l一直指向的就是第一个节点

             void linkLast(E e) {
                // 在第一次进来的时候,因为last等于null,所以l此时就是null
                final Node<E> l = last;//此时last是空让l指向null
                // 然后这里就创建了一个节点,注意此时,他将l放在了创建出来的新节点的pre的位置,所以此时新节点的pre就指向了第一个节点
                final Node<E> newNode = new Node<>(l, e, null);
                // 然后让last指向了新的节点
                last = newNode;
                // 这里判断l是否为null 此时l肯定为null 所以让first也指向了创建出来的新节点
                if (l == null)
                    first = newNode;
                else
                    l.next = newNode;
                size++;
                modCount++;
            }

         */

        /*
          源码 linkedList.remove(); // 这里默认删除的是第一个结点
          1. 执行 removeFirst
            public E remove() {
                return removeFirst();
            }
         2. 执行
            public E removeFirst() {
                final Node<E> f = first;
                if (f == null)
                    throw new NoSuchElementException();
                return unlinkFirst(f);
            }
          3. 执行 unlinkFirst, 将 f 指向的双向链表的第一个结点拿掉


// 在删除元素的时候会先进行把你要删除的那个节点中的元素保存到一个element中,也就时这一句话final E element = f.item;
// 紧接着就是final Node<E> next = f.next;让next指向下一个节点
// 然后就是把第一个节点保存元素的地方置空,把第一个节点指向下一个节点也置空    f.item = null; f.next = null; // help GC  也就是这两句话
// help GC的意思是,把第一个节点置空了,系统会回收
// first = next;然后就是让first指向下一个节点
// 这个时候判断next是不是null。很显然next不为空因此执行next.prev = null;把next指向前一个节点的pre也置空,这样也就完成了删除
// size表示的当前海还剩下了多少个元素  modCount表示当前操作过几次


            private E unlinkFirst(Node<E> f) {
                // assert f == first && f != null;
                // 先将节点中的内容存放到item中
                final E element = f.item;
                然后让next指向下一个节点
                final Node<E> next = f.next;
                f.item = null;
                f.next = null; // help GC
                first = next;
                if (next == null)
                    last = null;
                else
                    next.prev = null;
                size--;
                modCount++;
                // 最后返回的是你删除的那个元素
                return element;
            }
         */
    }
}